package cc.rengu.igas.bsps.core.service.trans;

import cc.rengu.igas.acct.facade.request.VirtAcctPreAuthCancelRequest;
import cc.rengu.igas.acct.facade.request.VirtAcctPreAuthCompRequest;
import cc.rengu.igas.acct.facade.response.VirtAcctPreAuthCancelResponse;
import cc.rengu.igas.acct.facade.response.VirtAcctPreAuthCompResponse;
import cc.rengu.igas.acct.facade.result.Result;
import cc.rengu.igas.bsps.common.constant.BspsAppParamConstant;
import cc.rengu.igas.bsps.common.constant.BspsTreeNodeConstant;
import cc.rengu.igas.bsps.common.constant.DubboMethodConstant;
import cc.rengu.igas.bsps.common.enums.RespCodeEnum;
import cc.rengu.igas.share.core.model.MchntInfo;
import cc.rengu.igas.share.core.realize.MchntService;
import cc.rengu.igas.share.core.realize.impl.MchntServiceImpl;
import cc.rengu.igas.smps.facade.base.Header;
import cc.rengu.igas.smps.facade.request.TransResultNoticeRequest;
import cc.rengu.igas.smps.facade.response.TransResultNoticeResponse;
import cc.rengu.oltp.service.base.RadpService;
import cc.rengu.oltp.service.common.constant.AppParamConstant;
import cc.rengu.oltp.service.common.constant.TreeNodeConstant;
import cc.rengu.oltp.service.common.dao.PayOrderInfoMapper;
import cc.rengu.oltp.service.common.dao.impl.PayOrderInfoMapperImpl;
import cc.rengu.oltp.service.common.entity.ChannelCallCfg;
import cc.rengu.oltp.service.common.entity.MchntOrderInfo;
import cc.rengu.oltp.service.common.entity.PayOrderInfo;
import cc.rengu.oltp.service.common.entity.UserOrderInfo;
import cc.rengu.oltp.service.common.enums.BizStatusEnum;
import cc.rengu.oltp.service.common.enums.ChannelEnum;
import cc.rengu.oltp.service.common.enums.TransStatusEnum;
import cc.rengu.oltp.service.model.BizException;
import cc.rengu.oltp.service.model.TxnInfo;
import cc.rengu.oltp.service.realize.DubboService;
import cc.rengu.oltp.service.realize.OrderService;
import cc.rengu.oltp.service.realize.TxnInfoService;
import cc.rengu.oltp.service.realize.impl.DubboServiceImpl;
import cc.rengu.oltp.service.realize.impl.OrderServiceImpl;
import cc.rengu.oltp.service.realize.impl.TxnInfoServiceImpl;
import cc.rengu.oltp.utility.util.*;
import com.alibaba.fastjson.JSON;
import org.springframework.util.CollectionUtils;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author: zhangxuran
 * @Date: 2020/5/14 23:30
 * @Description: 虚拟账户预授权后续处理
 */
public class AsynMchntVirtAcctPreHandleService extends RadpService {

    @Override
    protected int bizInit(String s) {
        return 0;
    }

    @Override
    protected int bizProcess(String s, int i) {

        XmlTreeUtil xmlTreeUtil = new XmlTreeUtil();
        try {
            MchntOrderInfo mchntOrderInfo = (MchntOrderInfo) xmlTreeUtil.getXmlTreeObjectValue(BspsTreeNodeConstant.MCHNT_ORDER_INFO, MchntOrderInfo.class);
            UserOrderInfo userOrderInfo = (UserOrderInfo) xmlTreeUtil.getXmlTreeObjectValue(BspsTreeNodeConstant.USER_ORDER_INFO, UserOrderInfo.class);
            String payType = xmlTreeUtil.getXmlTreeStringValue(TreeNodeConstant.PAY_TYPE);
            if (null == mchntOrderInfo || null == userOrderInfo) {
                rglog.error("商户订单或支付订单为空，异步进行虚拟账户预授权完成/撤销失败");
                return -1;
            }
            String sysSeqNum = mchntOrderInfo.getSysSeqNum();

            OrderService orderService = new OrderServiceImpl();

            //获取交易配置信息
            TxnInfoService txnInfoService = new TxnInfoServiceImpl();
            TxnInfo txnInfo = txnInfoService.getTxnInfo(userOrderInfo.getInstId(), userOrderInfo.getMsgSrcId(), userOrderInfo.getTransChannelId(), userOrderInfo.getTxnNum(), userOrderInfo.getBizType());

            PayOrderInfoMapper payOrderInfoMapper = new PayOrderInfoMapperImpl();
            List<PayOrderInfo> payOrderInfoList = payOrderInfoMapper.selectPayOrderInfoBySysSeqNum(mchntOrderInfo.getInstId(), mchntOrderInfo.getSysSeqNum());
            if (CollectionUtils.isEmpty(payOrderInfoList)) {
                rglog.error("该支付订单为空, sysSeqNum:<{}>", sysSeqNum);
                return -1;
            }
            //预授权
            Optional<PayOrderInfo> prePayOrderInfoOptional = payOrderInfoList.stream()
                    .filter(item -> ChannelEnum.ACCT.getChannelType().equals(item.getMsgDstId()) && "P06AT100".equals(item.getDstTxnNum())
                            && TransStatusEnum.TRANS_SUCC.getStatus().equals(item.getTransStatus()) && BizStatusEnum.FINISH.getStatus().equals(item.getBizStatus())).findFirst();
            if (!prePayOrderInfoOptional.isPresent()) {
                rglog.error("支付订单表无预授权 dstTxnNum为P06AT100的交易状态为成功且业务状态为处理成功的虚拟账户预授权数据！,sysSeqNum:<{}>,",
                        sysSeqNum);
                return -1;
            }
            PayOrderInfo preOrderInfo = prePayOrderInfoOptional.get();

            MchntService mchntService = new MchntServiceImpl();
            MchntInfo mchntInfo = mchntService.getMchntInfo(mchntOrderInfo.getInstId(), mchntOrderInfo.getMchntNo());
            if (null == mchntInfo) {
                rglog.error("获取商户信息失败,mchntNo:<{}>", mchntOrderInfo.getMchntNo());
                throw new BizException(RespCodeEnum.MCHNT_INFO_NOT_FOUND.getRespCode(), RespCodeEnum.MCHNT_INFO_NOT_FOUND.getRespDesc());
            }
            if (BizStatusEnum.FINISH.getStatus().equals(mchntOrderInfo.getBizStatus())) {
                /* step8： 新增支付订单（预授权完成） */
                PayOrderInfo acctAuthCompPayOrderInfo = initAcctPayOrderInfo(mchntOrderInfo, "P06AT500", txnInfo, preOrderInfo.getChannelSeqNum());
                boolean dbResult = orderService.registerOrderInfo(null, null, acctAuthCompPayOrderInfo);
                if (!dbResult) {
                    rglog.error("提现交易成功，新增预授权完成支付订单信息失败！instId:<{}>，sysSeqNum：<{}>", mchntOrderInfo.getInstId(), mchntOrderInfo.getSysSeqNum());
                    throw new BizException(RespCodeEnum.INSERT_ORDER_INFO_ERROR.getRespCode(), RespCodeEnum.INSERT_ORDER_INFO_ERROR.getRespDesc());
                }

                /*  step9： 调用虚拟账户进行预授权完成 */
                DubboService dubboService = new DubboServiceImpl();
                VirtAcctPreAuthCompRequest virtAcctPreAuthCompRequest = new VirtAcctPreAuthCompRequest();
                cc.rengu.igas.acct.facade.base.Header header = new cc.rengu.igas.acct.facade.base.Header();
                header.setInstId(userOrderInfo.getInstId());
                header.setTxnNum(acctAuthCompPayOrderInfo.getDstTxnNum());
                header.setTraceNo(acctAuthCompPayOrderInfo.getChannelSeqNum());
                header.setSrcSysId(AppParamConstant.SYS_ID);
                header.setChanlId(BspsAppParamConstant.BSP_SYS_ID);
                header.setTransTime(DateUtil.getCurrentTime());
                header.setTransDate(DateUtil.getCurrentDate());
                virtAcctPreAuthCompRequest.setHeader(header);
                virtAcctPreAuthCompRequest.setAcctType("00");
                //userType : 00-商户  01-会员 02-营销
                virtAcctPreAuthCompRequest.setUserType("00");
                virtAcctPreAuthCompRequest.setTransAmt(acctAuthCompPayOrderInfo.getRealPayAmt());
                virtAcctPreAuthCompRequest.setUserId(mchntOrderInfo.getMchntNo());
                virtAcctPreAuthCompRequest.setFreezeAcctSeqNum(preOrderInfo.getChannelOrderId());
                if (BspsAppParamConstant.FLAG_N.equals(mchntInfo.getIndependentDataFlag())) {
                    //非独立维护，填连锁商户号
                    virtAcctPreAuthCompRequest.setUserId(mchntInfo.getChainMchntNo());
                }

                Result<VirtAcctPreAuthCompResponse> acctDubboResult = (Result<VirtAcctPreAuthCompResponse>) dubboService.callDubboService(DubboMethodConstant.DUBBO_VIRT_ACCT_SERVICE, "virtAcctPreAuthComp", virtAcctPreAuthCompRequest);
                VirtAcctPreAuthCompResponse virtAcctPreAuthCompResponse = acctDubboResult.getResult();
                //00 - 记账成功
                if (acctDubboResult.isSuccess() && "00".equals(virtAcctPreAuthCompResponse.getTransStatus())) {
                    //更新 虚拟账户预授权完成-支付订单为成功
                    acctAuthCompPayOrderInfo.setTransStatus(TransStatusEnum.TRANS_SUCC.getStatus());
                    acctAuthCompPayOrderInfo.setBizStatus(BizStatusEnum.FINISH.getStatus());
                    acctAuthCompPayOrderInfo.setRespDesc(virtAcctPreAuthCompResponse.getRespDesc());
                    acctAuthCompPayOrderInfo.setRespCode(virtAcctPreAuthCompResponse.getRespCode());
                    acctAuthCompPayOrderInfo.setSettleDate(virtAcctPreAuthCompResponse.getAcctDate());
                    if (!StringUtil.isEmptyOrNull(virtAcctPreAuthCompResponse.getAcctSeqNum())) {
                        acctAuthCompPayOrderInfo.setChannelSeqNum(virtAcctPreAuthCompResponse.getAcctSeqNum());
                    }
                    acctAuthCompPayOrderInfo.setUpdateTime(DateUtil.getCurrentDateTime(BspsAppParamConstant.yyyy_MM_dd_HHmmssSSS));
                    mchntOrderInfo.setVirtualAcctBalance(virtAcctPreAuthCompResponse.getAfterBalance());

                    dbResult = orderService.updateOrderInfo(null, Arrays.asList(mchntOrderInfo), acctAuthCompPayOrderInfo);
                    if (!dbResult) {
                        rglog.error("更新虚拟账户预授权完成-支付订单状态为成功的数据库操作失败！instId:<{}>，sysSeqNum：<{}>", mchntOrderInfo.getInstId(), mchntOrderInfo.getSysSeqNum());
                        throw new BizException(RespCodeEnum.UPDATE_ORDER_STATUS_ERROR.getRespCode(), RespCodeEnum.UPDATE_ORDER_STATUS_ERROR.getRespDesc());
                    }

                    //交易成功，进行结果推送
                    return msgPushToMchnt(xmlTreeUtil);

                } else {
                    //更新 虚拟账户预授权完成-支付订单为失败
                    acctAuthCompPayOrderInfo.setTransStatus(TransStatusEnum.SYSTEM_REJECT.getStatus());
                    acctAuthCompPayOrderInfo.setBizStatus(BizStatusEnum.FAILED.getStatus());
                    acctAuthCompPayOrderInfo.setRespDesc(acctDubboResult.getResult().getRespDesc());
                    acctAuthCompPayOrderInfo.setRespCode(acctDubboResult.getResult().getRespCode());
                    acctAuthCompPayOrderInfo.setSettleDate(virtAcctPreAuthCompResponse.getAcctDate());
                    if (!StringUtil.isEmptyOrNull(virtAcctPreAuthCompResponse.getAcctSeqNum())) {
                        acctAuthCompPayOrderInfo.setChannelOrderId(virtAcctPreAuthCompResponse.getAcctSeqNum());
                    }
                    acctAuthCompPayOrderInfo.setUpdateTime(DateUtil.getCurrentDateTime(BspsAppParamConstant.yyyy_MM_dd_HHmmssSSS));
                    dbResult = orderService.updateOrderInfo(null, null, acctAuthCompPayOrderInfo);
                    if (!dbResult) {
                        rglog.error("更新虚拟账户预授权完成-支付订单状态为失败的数据库操作失败！instId:<{}>，sysSeqNum：<{}>", mchntOrderInfo.getInstId(), mchntOrderInfo.getSysSeqNum());
                        throw new BizException(RespCodeEnum.UPDATE_ORDER_STATUS_ERROR.getRespCode(), RespCodeEnum.UPDATE_ORDER_STATUS_ERROR.getRespDesc());
                    }
                }
            } else {
                /*  新增支付订单（预授权撤销） */
                PayOrderInfo acctAuthCancelPayOrderInfo = initAcctPayOrderInfo(mchntOrderInfo, "P06AT300", txnInfo, preOrderInfo.getChannelSeqNum());
                boolean dbResult = orderService.registerOrderInfo(null, null, acctAuthCancelPayOrderInfo);
                if (!dbResult) {
                    rglog.error("新增用户订单，商户订单，支付订单失败，提现交易失败！instId:<{}>，sysSeqNum：<{}>", mchntOrderInfo.getInstId(), mchntOrderInfo.getSysSeqNum());
                    throw new BizException(RespCodeEnum.INSERT_ORDER_INFO_ERROR.getRespCode(), RespCodeEnum.INSERT_ORDER_INFO_ERROR.getRespDesc());
                }

                /*  调用虚拟账户进行预授权撤销 */
                /*  step9： 调用虚拟账户进行预授权撤销 */
                VirtAcctPreAuthCancelRequest virtAcctPreAuthCancelRequest = new VirtAcctPreAuthCancelRequest();
                cc.rengu.igas.acct.facade.base.Header header = new cc.rengu.igas.acct.facade.base.Header();
                header.setInstId(userOrderInfo.getInstId());
                header.setTxnNum(acctAuthCancelPayOrderInfo.getDstTxnNum());
                header.setTraceNo(acctAuthCancelPayOrderInfo.getChannelSeqNum());
                header.setSrcSysId(AppParamConstant.SYS_ID);
                header.setChanlId(BspsAppParamConstant.BSP_SYS_ID);
                header.setTransTime(DateUtil.getCurrentTime());
                header.setTransDate(DateUtil.getCurrentDate());
                virtAcctPreAuthCancelRequest.setHeader(header);
                virtAcctPreAuthCancelRequest.setAcctType("00");
                //userType : 00-商户  01-会员 02-营销
                virtAcctPreAuthCancelRequest.setUserType("00");
                virtAcctPreAuthCancelRequest.setTransAmt(acctAuthCancelPayOrderInfo.getRealPayAmt());
                virtAcctPreAuthCancelRequest.setUserId(mchntOrderInfo.getMchntNo());
                virtAcctPreAuthCancelRequest.setFreezeAcctSeqNum(preOrderInfo.getChannelOrderId());
                if (BspsAppParamConstant.FLAG_N.equals(mchntInfo.getIndependentDataFlag())) {
                    //非独立维护，填连锁商户号
                    virtAcctPreAuthCancelRequest.setUserId(mchntInfo.getChainMchntNo());
                }

                DubboService dubboService = new DubboServiceImpl();
                Result<VirtAcctPreAuthCancelResponse> acctDubboResult = (Result<VirtAcctPreAuthCancelResponse>) dubboService.callDubboService(DubboMethodConstant.DUBBO_VIRT_ACCT_SERVICE, "virtAcctPreAuthCancel", virtAcctPreAuthCancelRequest);
                VirtAcctPreAuthCancelResponse cancelResponse = acctDubboResult.getResult();
                if (acctDubboResult.isSuccess() && "00".equals(cancelResponse.getTransStatus())) {
                    //更新 虚拟账户预授权撤销-支付订单为成功
                    acctAuthCancelPayOrderInfo.setTransStatus(TransStatusEnum.TRANS_SUCC.getStatus());
                    acctAuthCancelPayOrderInfo.setBizStatus(BizStatusEnum.FINISH.getStatus());
                    acctAuthCancelPayOrderInfo.setRespDesc(cancelResponse.getRespDesc());
                    acctAuthCancelPayOrderInfo.setRespCode(cancelResponse.getRespCode());
                    acctAuthCancelPayOrderInfo.setSettleDate(cancelResponse.getAcctDate());
                    if (!StringUtil.isEmptyOrNull(cancelResponse.getAcctSeqNum())) {
                        acctAuthCancelPayOrderInfo.setChannelOrderId(cancelResponse.getAcctSeqNum());
                    }
                    acctAuthCancelPayOrderInfo.setUpdateTime(DateUtil.getCurrentDateTime(BspsAppParamConstant.yyyy_MM_dd_HHmmssSSS));
                    dbResult = orderService.updateOrderInfo(null, null, acctAuthCancelPayOrderInfo);
                    if (!dbResult) {
                        rglog.error("更新虚拟账户预授权撤销-支付订单状态为成功的数据库操作失败！instId:<{}>，sysSeqNum：<{}>", mchntOrderInfo.getInstId(), mchntOrderInfo.getSysSeqNum());
                        throw new BizException(RespCodeEnum.UPDATE_ORDER_STATUS_ERROR.getRespCode(), RespCodeEnum.UPDATE_ORDER_STATUS_ERROR.getRespDesc());
                    }
                } else {
                    //更新 虚拟账户预授权撤销-支付订单为失败
                    acctAuthCancelPayOrderInfo.setTransStatus(TransStatusEnum.SYSTEM_REJECT.getStatus());
                    acctAuthCancelPayOrderInfo.setBizStatus(BizStatusEnum.FAILED.getStatus());
                    acctAuthCancelPayOrderInfo.setRespDesc(acctDubboResult.getResult().getRespDesc());
                    acctAuthCancelPayOrderInfo.setRespCode(acctDubboResult.getResult().getRespCode());
                    acctAuthCancelPayOrderInfo.setUpdateTime(DateUtil.getCurrentDateTime(BspsAppParamConstant.yyyy_MM_dd_HHmmssSSS));
                    dbResult = orderService.updateOrderInfo(null, null, acctAuthCancelPayOrderInfo);
                    if (!dbResult) {
                        rglog.error("更新虚拟账户预授权撤销-支付订单状态为失败的数据库操作失败！instId:<{}>，sysSeqNum：<{}>", mchntOrderInfo.getInstId(), mchntOrderInfo.getSysSeqNum());
                        throw new BizException(RespCodeEnum.UPDATE_ORDER_STATUS_ERROR.getRespCode(), RespCodeEnum.UPDATE_ORDER_STATUS_ERROR.getRespDesc());
                    }
                }
            }
        } catch (Exception e) {
            return -1;
        }


        return 0;
    }

    private int msgPushToMchnt(XmlTreeUtil xmlTreeUtil) throws Exception {
        //交易成功，进行消息推送
        //推送商户入账结果通知
        Header header = new Header();
        ConvertUtil.convertOutput(header);
        header.setSrcSysId(BspsAppParamConstant.BSP_SYS_ID);
        header.setBizType(BspsAppParamConstant.DUBBO_DEFAULT_BIZ_TYPE);
        header.setTxnNum("");

        TransResultNoticeRequest dubboRequest = new TransResultNoticeRequest();
        //TODO 消息推送标识
        dubboRequest.setPushMsgId("?");

        //TODO 推送消息内容
        dubboRequest.setContent("交易成功");

        DubboService dubboService = new DubboServiceImpl();
        cc.rengu.igas.smps.facade.result.Result<TransResultNoticeResponse> result = (cc.rengu.igas.smps.facade.result.Result<TransResultNoticeResponse>) dubboService.callDubboService(DubboMethodConstant.MSG_PUSH_SERVICE, "mchntTransResultNotice", dubboRequest);
        if (null == result || !result.isSuccess()) {
            rglog.info("商户交易结果通知DUBBO接口-调用失败");
            return -1;
        }
        TransResultNoticeResponse response = result.getResult();
        if (BspsAppParamConstant.DUBBO_OVERTIME.equals(response.getRespCode())) {
            rglog.info("商户交易结果通知DUBBO接口-调用超时，respCode:<{}>,respDesc:<{}>", response.getRespCode(), response.getRespDesc());
            return -1;
        } else if (!BspsAppParamConstant.DUBBO_SUCCESS.equals(response.getRespCode())) {
            rglog.info("商户交易结果通知DUBBO接口-调用失败，respCode:<{}>,respDesc:<{}>", response.getRespCode(), response.getRespDesc());
            return -1;
        } else {
            rglog.info("商户交易结果通知DUBBO接口-调用成功，respCode:<{}>,respDesc:<{}>", response.getRespCode(), response.getRespDesc());
            xmlTreeUtil.setXmlTreeStringValue(BspsAppParamConstant.MSG_PUSH_RESULT, response.getPushResult());
            return 0;
        }
    }

    @Override
    protected int bizTerminate(String s) {
        return 0;
    }

    private PayOrderInfo initAcctPayOrderInfo(MchntOrderInfo mchntOrderInfo,
                                              String dstTxnNum, TxnInfo txnInfo, String oriSysSeqNum) throws Exception {

        List<ChannelCallCfg> channelCallCfgList = txnInfo.getChannelCallCfgList().stream().filter(item -> item.getCallChannelId().equals(ChannelEnum.ACCT.getChannelType())).collect(Collectors.toList());

        Optional<ChannelCallCfg> channelCallCfgOptional = channelCallCfgList.stream()
                .filter(item -> ChannelEnum.ACCT.getChannelType().equals(item.getCallChannelId()) && dstTxnNum.equals(item.getCallChannelTxn())).findFirst();
        if (!channelCallCfgOptional.isPresent()) {
            rglog.error("通道服务调用配置表无dstTxnNum为{}的虚拟账户预授权/撤销数据！,sysSeqNum:<{}>,",
                    dstTxnNum, mchntOrderInfo.getSysSeqNum());
            throw new BizException(RespCodeEnum.CHANNEL_CONFIG_NOT_EXIST.getRespCode(), RespCodeEnum.CHANNEL_CONFIG_NOT_EXIST.getRespDesc());
        }

        //获取通道服务调用配置
        ChannelCallCfg channelCallCfg = channelCallCfgOptional.get();

        PayOrderInfo payOrderInfo = new PayOrderInfo();
        ConvertUtil.convertOutput(payOrderInfo);
        payOrderInfo.setTxnNum(mchntOrderInfo.getTxnNum());
        payOrderInfo.setSysSeqNum(mchntOrderInfo.getSysSeqNum());
        payOrderInfo.setMchntOrderId(mchntOrderInfo.getMchntOrderId());
        payOrderInfo.setOrderAmt(mchntOrderInfo.getOrderAmt());
        //虚拟账户 记账金额
        payOrderInfo.setRealPayAmt(mchntOrderInfo.getRealSettleAmt());
        //交易通道标识
        payOrderInfo.setMsgDstId(channelCallCfg.getCallChannelId());
        //支付通道流水号
        String channelSeqNum = mchntOrderInfo.getSysSeqNum() + channelCallCfg.getCallIndex();
        payOrderInfo.setChannelSeqNum(channelSeqNum);
        //支付通道对账唯一KEY  虚拟账户：系统流水号+调用序号
        payOrderInfo.setChannelReconKey(channelSeqNum);
        //通道调用序号
        payOrderInfo.setDstCallIndex(channelCallCfg.getCallIndex());
        //通道交易码
        payOrderInfo.setDstTxnNum(channelCallCfg.getCallChannelTxn());
        payOrderInfo.setTransStatus(TransStatusEnum.TRANS_INIT.getStatus());
        payOrderInfo.setBizStatus(BizStatusEnum.PROCESSING.getStatus());
        //虚拟账户 payType = *
        payOrderInfo.setPayType("*");
        payOrderInfo.setCreateTime(DateUtil.getCurrentDateTime(BspsAppParamConstant.yyyy_MM_dd_HHmmssSSS));
        return payOrderInfo;
    }


}
